package jpave.annotator;

import java.io.*;
import java.util.HashMap;
import java.util.Vector;
import java.lang.Character;

import jpave.database.CoreDBWrapper;
import jpave.dataholders.CodingRegion;
import jpave.dataholders.ContigData;
import jpave.dataholders.SequenceData;
import util.Debug.ErrorReport;

/**********************************************************
 * CAS I was going to fix computing ORFs, but as we are moving to OCW, it can wait.
 * but not ready to totally delete this....
 * 1. if a file is entered of AA sequences, get reading frame from each
 * 2. Get best RF over all protein hits
 * 3. Get best RF over all pairwise
 * 4. Get ORF - must have start or stop
 * 5. Determine best reading frame
 * 6. Later - compute codon and triples to use for ambiguous ones
 */
public class DoAA {

	static public void DoORF(ContigData ctgObj) {
		//ctgObj.setLargestCoding(coding);
	}
	
	// requires a complete ORF, i.e. both start and stop codon
	static private int [] findBestORFs(String seq, int frame) {
		Vector<CodingRegion> ORFs = new Vector<CodingRegion>();

		String ntSeq = seq;
		int seqLen = seq.length();
		
		// reverse complement
		if (frame < 0) {
			String cSeq="";
			seq = seq.toUpperCase();
			
			for (int i = seq.length() - 1; i >= 0; --i) {
				char base = 'N';
				if (seq.charAt(i) == 'A') base = 'T';
				else if (seq.charAt(i) == 'T') base = 'A';
				else if (seq.charAt(i) == 'C') base = 'G';
				else if (seq.charAt(i) == 'G') base = 'C';
				cSeq += base;
			}
			ntSeq = cSeq;
		}
 
		int bestStart = 0;
		int bestEnd = 0;
		int bestLen = 0;

		int arf = Math.abs(frame);
		int nStart = -1;
		int nEnd = seqLen; 
		int nLen = 0;
			
		for (int i = arf - 1; i < (seqLen-2); i += 3) {

			if (nStart < 0 && seq.charAt(i) == 'A' && seq.charAt(i+1) == 'T' && seq.charAt(i+2) == 'G') {
				nStart = i + 1; 
			}
			else if (nStart >= 0 && seq.charAt(i) == 'T') {
				boolean stop = false;
				if      (seq.charAt(i+1) == 'A' && seq.charAt(i+2) == 'A') stop=true;
				else if (seq.charAt(i+1) == 'A' && seq.charAt(i+2) == 'G') stop=true;
				else if (seq.charAt(i+1) == 'G' && seq.charAt(i+2) == 'A') stop=true;
				if (stop) {
					nEnd = i + 3;
					nLen = (nEnd - nStart);
					if (bestLen < nLen) {
						bestStart = nStart;
						bestEnd = nEnd;
						bestLen = nLen;
					}
				}
				nStart = -1;
				nEnd = seqLen;
			}
		}
	
		int [] x = new int [3];
		x[0] = bestStart; x[1] = bestEnd; x[2] = bestLen;
		return x;
	}
	// ContigData - the nQStart and nQend are the 
	// positions on the unitrans that the protein aligned
	/**public CodingRegion findEnclosingORF(int nQStart, int nQEnd) {	
		int seqLen = strSequence.length();
		String strSeq = strSequence;
		
		int orient = 1;	
		if (nQEnd <= nQStart) { // flip
			nQStart = seqLen - nQStart +1;
			nQEnd = seqLen - nQEnd + 1;
			strSeq = SequenceData.getSequenceReverseComplement(strSeq);
			orient = -1;
		}
		if ((nQEnd - nQStart + 1) % 3 != 0) {
			System.err.println("Internal error: Blast query start/end have mis-matched frames: nQStart="
							+ nQStart + " nQEnd=" + nQEnd);
		}
		
		int arf = nQStart % 3;
		if (arf==0) arf = 3;
		int frame = arf;
		if (orient<0) frame = -arf;
		
		// Extend the match as far as possible on the 5' side
		int nStart = arf+1; // -1 is subtracted for display
		int tmpStart = 0;
		for (int i = nQStart - 1; i >= 0; i -= 3) {
			if (haveStartAt(strSeq, i)) {
				tmpStart = i + 1;
			} else if (haveStopAt(strSeq, i)) {
				if (tmpStart == 0) nStart = nQStart;
				else nStart = tmpStart;
				break;
			}
		}
		
		// Look for the stop codon moving out (extend on 3' side)
		int nEnd = 0;
		int last = seqLen;
		for (int i = nQEnd + 1 - 1; i < (seqLen - 2); i += 3) {
			if (haveStopAt(strSeq, i)) {
				nEnd = i + 3;
				break;
			}
			last = i + 3;
		}
		if (nEnd==0) nEnd = last;

		return createORF(CodingRegion.TYPE_UNIPROT, 
					nStart, nEnd, frame);
	}
	public DoAA (CoreDBWrapper sObj) {
		sqlObj = sObj;
		try {
			processContigs();
			sqlObj.aaWritefile(ctgMap, new File("unitransAA.fasta"));
		}
		catch (Exception e) {}
	}
	
	private void processContigs() {
		ctgMap = new HashMap<String, String> ();
		ctgVec = new Vector <String> ();
		
		try {
			sqlObj.aaloadCtgORF(ctgMap);
		}
		catch (Exception e) {
			ErrorReport.prtReport(e,  "Trying to get the contigs");
		}	
		
		try {
			for ( String ctgid : ctgMap.keySet() )
			{
				for (int i=0; i<7; i++) count[i]=0;			 
				evidence = "";
				
				String orf = ctgMap.get(ctgid); 

				String[] tok = orf.split(";");
				int frame = Integer.parseInt(tok[0]);
				int len = Integer.parseInt(tok[1]);
				int hasEnds = Integer.parseInt(tok[2]);
				int cntHits = Integer.parseInt(tok[3]);
				int cntPW = Integer.parseInt(tok[4]);
	
		// ORF frame
				if (hasEnds==2) {
					int score = (int) (((double) len / 100.0)+0.5) ;
					count[frame+3] += score+1;
					evidence = "ORF:"+frame+":"+len;
				}
				
		// Hit frame
				if (cntHits > 0) {
					getHitFrame(ctgid);
					frame = getFrame(cntPW); 
				}
				
		// Pairs frame
				if (cntPW > 0) {
					getPWFrame(ctgid);
					frame = getFrame(0);
				}			
				ctgMap.put(ctgid, Integer.toString(frame) + ";" + evidence);
			}
		}
		catch (Exception e) {
			ErrorReport.prtReport(e,  "Trying to get frames");
		}	
	}
	
	private void getHitFrame(String ctgid) {
		try {
			ctgVec.clear();
			int nHits = sqlObj.aaloadCtgHits(ctgid, ctgVec);

			int tot=0;
			int cnt [] = {0,0,0,0,0,0,0};
			
			for (int i=0; i < nHits && i < 10; i++) {
				String hit = ctgVec.get(i);

				String[] tok = hit.split(";");
				int s = Integer.parseInt(tok[0]);
				int e = Integer.parseInt(tok[1]);
				double eval = Double.parseDouble(tok[2]);
				int frame=0;
				
				if (s < e) {
					frame = s % 3;
					if (frame==0) frame=3;
				}
				else {
					frame = e % 3;
					if (frame==0) frame=3;
					frame = -frame;
				}
				int len = Math.abs(s-e) + 1;
				
				count[frame+3] += score(len, eval);
				cnt[frame+3]++;
				tot++;
			}
			int f=0, max=0;
			for (int i=0;  i<=6; i++) {
				if (cnt[i] > max) {
					f = i-3;
					max = cnt[i];
				}
			}
			evidence += " HITs:"+f+":"+max+"/" + tot;
		}
		catch (Exception e) {
			ErrorReport.prtReport(e,  "Trying to get Hit Frame");
		}		
	}
	
	private void getPWFrame(String ctgid) {
		try {
			ctgVec.clear();
			int nPW = sqlObj.aaloadCtgPairs(ctgid, ctgVec);
	
			int tot=0;
			int cnt [] = {0,0,0,0,0,0,0};
			
			for (int i=0; i < nPW && i < 5; i++) {
				String hit = ctgVec.get(i);

				String[] tok = hit.split(";");
				int frame = Integer.parseInt(tok[0]);
				int len = Integer.parseInt(tok[1]);
				double eval = Double.parseDouble(tok[2]);
				
				count[frame+3] += score(len, eval);
				cnt[frame+3]++;
				tot++;
			}
			
			int f=0, max=0;
			for (int i=0;  i<=6; i++) {
				if (cnt[i] > max) {
					f = i-3;
					max = cnt[i];
				}
			}
			evidence += " PAIRs:"+f+":"+max+"/" + tot;
		}
		catch (Exception e) {
			ErrorReport.prtReport(e,  "Trying to get Pair Frame");
		}
	}
	// heuristics
	private int score(int len, double e) {
		if (e==0.0 && len > 300) return 10;
		if (e< 100 && len > 300) return 8;
		if (e< 80  && len > 300) return 6;
		if (e==0.0 && len > 200) return 6;
		if (e==0.0) return 4;
		return 1;
	}
	
	private int getFrame(int best) {
		int num=0, max=0, frame=0;
		for (int i=0;  i<=6; i++) {
			if (count[i]>0) {
				num++;
				if (count[i] > max) {
					frame = i-3;
					max = count[i];
				}
			}
		}
		if (best>0) {
			if (num == 1 && max >= 6) return frame;
			if (max >= 10) return frame;
		}
		return frame;
	}
	**/
	String evidence = null;
	int count [] = {0,0,0,0,0,0,0};
	Vector <String> ctgVec;
	HashMap<String, String> ctgMap;
	CoreDBWrapper sqlObj;
}
